package io.renren.system.security.controller;

import io.renren.common.exception.ErrorCode;
import io.renren.common.exception.RenException;
import io.renren.common.utils.IpUtils;
import io.renren.common.utils.JsencryptUtils;
import io.renren.common.utils.Result;
import io.renren.common.validator.AssertUtils;
import io.renren.common.validator.ValidatorUtils;
import io.renren.system.log.entity.SysLogLoginEntity;
import io.renren.system.log.enums.LoginOperationEnum;
import io.renren.system.log.enums.LoginStatusEnum;
import io.renren.system.log.service.SysLogLoginService;
import io.renren.system.security.dto.LoginDTO;
import io.renren.system.security.password.PasswordUtils;
import io.renren.system.security.service.CaptchaService;
import io.renren.system.security.service.SysUserTokenService;
import io.renren.system.security.user.SecurityUser;
import io.renren.system.security.user.UserDetail;
import io.renren.system.sys.dto.SysUserDTO;
import io.renren.system.sys.enums.UserStatusEnum;
import io.renren.system.sys.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Map;

/**
 * 【登录管理】
 */
@RestController
@Api(tags = "【登录管理】")
public class LoginController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserTokenService sysUserTokenService;
    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private SysLogLoginService sysLogLoginService;

    @GetMapping("captcha")
    @ApiOperation(value = "验证码", produces = "application/octet-stream")
    @ApiImplicitParam(paramType = "query", dataType = "string", name = "uuid", required = true)
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        //uuid不能为空
        AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
        //生成验证码
        captchaService.create(response, uuid);
    }

    @PostMapping("login")
    @ApiOperation(value = "普通登录")
    public Result login(HttpServletRequest request, @RequestBody LoginDTO login) {
        //效验数据
        ValidatorUtils.validateEntity(login);

        String uuid = login.getUuid();
        String captcha = login.getCaptcha();
        String username = login.getUsername();
        String password = login.getPassword();

        // 用户名或密码解密
        username = JsencryptUtils.decryptRSADefault(username);
        password = JsencryptUtils.decryptRSADefault(password);

        //验证码是否正确
        boolean flag = captchaService.validate(uuid, captcha);
        if (!flag) {
            return new Result().error(ErrorCode.CAPTCHA_ERROR);
        }
        //用户信息
        SysUserDTO user = sysUserService.getByUsername(username);
        SysLogLoginEntity logLogin = new SysLogLoginEntity();
        logLogin.setOperation(LoginOperationEnum.LOGIN.value());
        logLogin.setCreateDate(new Date());
        logLogin.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        logLogin.setIp(IpUtils.getIpAddr(request));
        //用户不存在
        if (user == null) {
            logLogin.setStatus(LoginStatusEnum.FAIL.value());
            logLogin.setCreatorName(username);
            sysLogLoginService.save(logLogin);
            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }
        //密码错误
        if (!PasswordUtils.matches(password, user.getPassword())) {
            logLogin.setStatus(LoginStatusEnum.FAIL.value());
            logLogin.setCreator(user.getId());
            logLogin.setCreatorName(user.getUsername());
            sysLogLoginService.save(logLogin);
            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }

        //账号停用
        if (user.getStatus() == UserStatusEnum.DISABLE.value()) {
            logLogin.setStatus(LoginStatusEnum.LOCK.value());
            logLogin.setCreator(user.getId());
            logLogin.setCreatorName(user.getUsername());
            sysLogLoginService.save(logLogin);
            throw new RenException(ErrorCode.ACCOUNT_DISABLE);
        }

        //登录成功
        logLogin.setStatus(LoginStatusEnum.SUCCESS.value());
        logLogin.setCreator(user.getId());
        logLogin.setCreatorName(user.getUsername());
        sysLogLoginService.save(logLogin);

        Result token = sysUserTokenService.createToken(user.getId());
        Map<String, Object> map = (Map<String, Object>) token.getData();
        user.setToken((String) map.get("token"));
        user.setExpire((Integer) map.get("expire"));

        // 设置最后登录时间和登录地址
        sysUserService.setLastLoginTimeAndIp(user.getId(), logLogin);
        return new Result().ok(user);
    }

    @PostMapping("loginNoCaptcha")
    @ApiOperation(value = "不需要验证码登录")
    public Result loginNoCaptcha(HttpServletRequest request, @RequestBody LoginDTO login) {
        System.out.println("不需要验证码登录：" + login);
        //效验数据
        ValidatorUtils.validateEntity(login);

        String username = login.getUsername();
        String password = login.getPassword();

        // 用户名或密码解密
        username = JsencryptUtils.decryptRSADefault(username);
        password = JsencryptUtils.decryptRSADefault(password);

        //用户信息
        SysUserDTO user = sysUserService.getByUsername(username);

        SysLogLoginEntity logLogin = new SysLogLoginEntity();
        logLogin.setOperation(LoginOperationEnum.LOGIN.value());
        logLogin.setCreateDate(new Date());
        logLogin.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        logLogin.setIp(IpUtils.getIpAddr(request));
        //用户不存在
        if (user == null) {
            logLogin.setStatus(LoginStatusEnum.FAIL.value());
            logLogin.setCreatorName(username);
            sysLogLoginService.save(logLogin);

            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }
        //密码错误
        if (!PasswordUtils.matches(password, user.getPassword())) {
            logLogin.setStatus(LoginStatusEnum.FAIL.value());
            logLogin.setCreator(user.getId());
            logLogin.setCreatorName(user.getUsername());
            sysLogLoginService.save(logLogin);

            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }

        //账号停用
        if (user.getStatus() == UserStatusEnum.DISABLE.value()) {
            logLogin.setStatus(LoginStatusEnum.LOCK.value());
            logLogin.setCreator(user.getId());
            logLogin.setCreatorName(user.getUsername());
            sysLogLoginService.save(logLogin);

            throw new RenException(ErrorCode.ACCOUNT_DISABLE);
        }

        //登录成功
        logLogin.setStatus(LoginStatusEnum.SUCCESS.value());
        logLogin.setCreator(user.getId());
        logLogin.setCreatorName(user.getUsername());
        sysLogLoginService.save(logLogin);
        Result token = sysUserTokenService.createToken(user.getId());
        Map<String, Object> map = (Map<String, Object>) token.getData();
        user.setToken((String) map.get("token"));
        user.setExpire((Integer) map.get("expire"));

        // 设置最后登录时间和登录地址
        sysUserService.setLastLoginTimeAndIp(user.getId(), logLogin);
        return new Result().ok(user);
    }

    @PostMapping("logout")
    @ApiOperation(value = "退出")
    public Result logout(HttpServletRequest request) {
        UserDetail user = SecurityUser.getUser();
        //退出
        sysUserTokenService.logout(user.getId());
        //用户信息
        SysLogLoginEntity logLogin = new SysLogLoginEntity();
        logLogin.setOperation(LoginOperationEnum.LOGOUT.value());
        logLogin.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        logLogin.setIp(IpUtils.getIpAddr(request));
        logLogin.setStatus(LoginStatusEnum.SUCCESS.value());
        logLogin.setCreator(user.getId());
        logLogin.setCreatorName(user.getUsername());
        logLogin.setCreateDate(new Date());
        sysLogLoginService.save(logLogin);
        return new Result();
    }
}